/*
 * cxxomfort example: byte17
 *
 * This program provides sample usage of the cxxomfort backport
 * for C++17's std::byte type.
 *
 * The program will read text from the standard input, after that
 * will collect and map the frequencies of all
 * alphanumeric characters. The input is assumed to be in ASCII.
 *
 *
 *
 */

//#define CXXOMFORT_NOTICES 1
#include <cxxomfort/base.hpp>
#include <cxxomfort/cstddef.hpp>
#include <cxxomfort/library/type_name.hpp>
#include <cxxomfort/type_traits.hpp>
#include <cxxomfort/ostream.hpp>
#include <cassert>
#include <cstddef> // std::byte
#include <string>
#include <iostream>
#include <cstddef>
#include <iomanip>

void byte_traits();

// custom, unofficial std::byte stream output operator
static inline std::ostream& operator<< (std::ostream& os, std::byte const& b) {
    using namespace std;
    return os<< to_integer<unsigned char>(b);
}

int main () {
    using namespace std;
    cxxomfort::output_info();
    cout<< endl;
    using cxxomfort::fix::to_byte;
    struct bytetests {
		enum  BT1 {
			test1= std::is_same<unsigned char, std::byte>::value , 
			test2= std::is_arithmetic<byte>::value, 
		};
			
	} ;
	static_assert(bytetests::test1==false, "byte is a typedef!");
    static_assert(bytetests::test2==false, "byte not arithmetic!");
    
    byte S0 = to_byte(1);
    (void)S0;

    cout<< "unsigned char is : "
    << cxxomfort::type_name<unsigned char>()
    << endl;
    cout<< "byte is          : "
    << cxxomfort::type_name<byte>()
    << " , sizeof:"<< sizeof(byte)
    << " , alignof:"<< alignof(byte)<< endl;
    cout<< "byte implementation is: "<< (CXXOMFORT_IMPLEMENTS_byte)
        << " B"<< CXXO_IMPLSTATUS_BACKPORT()
        << " E"<< CXXO_IMPLSTATUS_EMULATION()
        << " N"<< CXXO_IMPLSTATUS_NATIVE()<< endl;

#if (CXXOMFORT_CXX_STD>=1997)
	std::byte by[2] = { to_byte(0x1), to_byte(0x2) };
	(void)by;
	cout<< "byte[2] : ";
	cout<< alignof(byte[2])<< endl;
	cout<< endl;
    // end section

    byte by0; (void)by0; // GCC7 check says it's default constructible
    byte by1 = to_byte(0x44);
    //byte err1 = (unsigned char)0x31; (void)err1; // should not compile
    //byte err1 ='a'; (void)err2a; // should not compile
    byte by2 = to_byte('2'); (void)by2;
    //byte by3a = 112; // should not compile
    byte by3 = to_byte(112);
    // according to cppreference and stackoverflow, the following two should work:
    byte by4 = to_byte(0x10); (void)by4;
    byte by5 = to_byte('a'); (void)by5;
    // ...but the following one is not guaranteed to:
    // byte errorfloat = to_byte(3.14f); (void)errorfloat;

#endif

    // byte by7a = 15.4f; (void)by7a; // should not work: conversion from scalar to non-scalar requested
    // byte errorfloat(15.4f); (void)errorfloat;

    byte by6 = to_byte('r'); (void)by6; // should not compile


    byte temp = by4;
    by1 |=by4;
    temp= temp | by3;
    by1 &= by5;
    temp= temp & by2;
    by1 ^= by6;


    byte a = to_byte(0x01);
    byte b = to_byte(0x3c);
    (void)b;
    byte c= a;
    (void)c;

    //a= 100; // should not compile;
    //a= (byte)'4'; // valid in c++17; can't be valid before with enum class
    a= to_byte(101u); // valid always
    assert (a == to_byte(101u));
    a= to_byte(0xcc);
    cout<< dec<< "Test: convert to char: "<< flush;
    unsigned char ca= explicit_cast<unsigned char>(a);
    printf("%02x", ca);
    cout<< endl;
    //cout<< a<< endl;

    cout<< "Test: convert to int: "<< endl;
    int aint =  to_integer<int>(a);
    cout<< "    a: "<< a<< endl;
    cout<< " aint: "<< aint<< endl;
    //cout<< (a == x) << endl;

    byte b1 = to_byte(0x5a);
    byte b2 = to_byte(0xa5);
    byte b3 = b1 ^ b2;
    byte b4 = b1 | b2;
    byte b5 = b1 >> 1;
    cout<< hex;
    cout<< to_integer<int>(b3)<< '\t';
    cout<< to_integer<int>(b4)<< '\t';
    cout<< to_integer<int>(b5)<< '\t';
    b5 = ~b5;
    cout<< to_integer<int>(b5)<< endl;

    cout<<  "Byte shuffling test: \t";
    cout<< dec;
    b1 = to_byte(0xff);
    while (to_integer<unsigned int>(b1)) {
        cout<< hex<< to_integer<int>(b1)<< dec<< " \t";
        b1>>= 2;
    }
    cout<< endl;

    cout<< "Byte cxxomfort additions test: "<< endl;

    // byte e1 = explicit_cast<byte>('X');
    //cout<< e1<< endl;
    cout<< endl;

#if (CXXOMFORT_CXX_STD >= 2011)
    cout<< "\n"<< "Byte constexpr test: "<< endl;
    constexpr byte c1 = to_byte(0x18);
    constexpr byte c2 = to_byte(0x51);
    static_assert ( c1 != c2 , "equality test 1");
    static_assert ( c2 == to_byte(0x51) , "equality test 2");
    constexpr byte c3 = c1 & c2;
    static_assert (c3 == to_byte(0x10), "logical AND test");
    constexpr byte c4 = ~c2;
    static_assert (c4 == to_byte(0xAE), "logical NOT test");
    

#endif

#ifdef PRINT_TRAITS_HPP
	cout<< "\nType Traits information:"<< endl;
	print_traits<byte>(cout);
	cout<< endl;
	print_traits_advanced<byte>(cout);
	cout<< endl;
	print_traits_construction<byte>(cout);
	cout<< endl;
	print_traits_cxxo<byte>(cout);
	cout<< endl;
#endif

}
